const db = require('../db/index.js');
const config = require('../config');

/**
 * 数据库查询封装函数
 * @param {string} sql - SQL查询语句
 * @param {Array} params - 查询参数
 * @returns {Promise} 查询结果
 */
const queryDb = (sql, params) => {
  return new Promise((resolve, reject) => {
    db.query(sql, params, (err, result) => {
      if (err) {
        console.error('数据库查询失败:', { sql, params, error: err.message });
        reject(err);
      } else {
        resolve(result);
      }
    });
  });
};

/**
 * 智能匹配优化器 - 使用内存索引加速匹配过程
 * 核心功能：构建课程-用户倒排索引，实现快速候选集筛选
 */
class MatchOptimizer {
  constructor() {
    // 核心索引结构
    this.courseUserIndex = new Map();    // 课程名称 -> 用户ID集合（倒排索引）
    this.userDataCache = new Map();      // 用户ID -> 用户完整数据（数据缓存）
    this.matchCache = new Map();         // 用户ID+参数 -> 匹配结果（结果缓存）
    
    // 索引管理参数
    this.lastIndexTime = 0;              // 最后索引构建时间
    this.indexTTL = 10 * 60 * 1000;      // 索引有效期10分钟
    this.isBuildingIndex = false;        // 防止重复构建索引的锁
    this.maxCacheSize = 10000;           // 最大缓存用户数量，防止内存溢出
    
    // 性能监控指标
    this.metrics = {
      totalQueries: 0,                   // 总查询次数
      cacheHits: 0,                      // 缓存命中次数
      indexBuilds: 0,                    // 索引构建次数
      lastBuildDuration: 0,              // 最后构建耗时
      lastBuildSuccess: true             // 最后构建是否成功
    };
    
    // 待处理的增量更新队列
    this.pendingUpdates = [];
  }

  /**
   * 构建全量内存索引 - 系统启动或定期更新时调用
   * 步骤：清空旧索引 → 查询有效用户 → 构建倒排索引 → 更新缓存
   */
  async buildIndex() {
    // 防止并发构建索引
    if (this.isBuildingIndex) {
      console.log('索引构建正在进行中，跳过本次构建');
      return;
    }
    
    this.isBuildingIndex = true;
    const startTime = Date.now();
    
    try {
      console.log('🚀 开始构建匹配索引...');
      
      // 步骤1：清空旧索引，准备构建新索引
      this.courseUserIndex.clear();
      this.userDataCache.clear();
      
      // 步骤2：批量获取所有有效用户数据
      // 只查询必要字段，减少内存占用和网络传输
      const usersSql = `
        SELECT 
          user_id, 
          grade, 
          study_time, 
          study_style, 
          communication_frequency, 
          selected_course_names, 
          student_id, 
          major, 
          avatar, 
          nickname
        FROM user_complete_profile 
        WHERE selected_course_names IS NOT NULL 
          AND selected_course_names != ''
          AND study_time IS NOT NULL
          AND study_style IS NOT NULL
        ORDER BY user_id DESC
        LIMIT ?  -- 限制最大用户数，防止内存溢出
      `;
      const users = await queryDb(usersSql, [this.maxCacheSize]);
      
      // 步骤3：构建倒排索引和数据缓存
      let totalCourses = 0;
      for (const user of users) {
        // 3.1 缓存用户数据
        this.userDataCache.set(user.user_id, user);
        
        // 3.2 处理用户课程，构建倒排索引
        const courses = user.selected_course_names.split(',');
        for (const course of courses) {
          const normalizedCourse = this.normalizeCourseName(course);
          
          // 初始化课程对应的用户集合
          if (!this.courseUserIndex.has(normalizedCourse)) {
            this.courseUserIndex.set(normalizedCourse, new Set());
          }
          
          // 将用户ID添加到该课程的索引中
          this.courseUserIndex.get(normalizedCourse).add(user.user_id);
          totalCourses++;
        }
        
        // 3.3 检查缓存大小，防止内存溢出
        if (this.userDataCache.size >= this.maxCacheSize) {
          console.warn(`⚠️ 达到最大缓存限制: ${this.maxCacheSize}，停止缓存更多用户`);
          break;
        }
      }
      
      // 步骤4：更新索引状态和监控指标
      this.lastIndexTime = Date.now();
      this.metrics.indexBuilds++;
      this.metrics.lastBuildDuration = Date.now() - startTime;
      this.metrics.lastBuildSuccess = true;
      
      console.log(`✅ 索引构建完成，耗时: ${this.metrics.lastBuildDuration}ms`);
      console.log(`📊 索引统计: 用户数=${users.length}, 课程数=${this.courseUserIndex.size}, 总课程记录=${totalCourses}`);
      
    } catch (error) {
      // 错误处理：记录失败状态并告警
      console.error('❌ 构建索引失败:', error);
      this.metrics.lastBuildSuccess = false;
      
      // 在实际生产环境中，这里可以发送告警通知
      // alertService.send('INDEX_BUILD_FAILED', error.message);
      
      throw error; // 重新抛出错误，让调用方处理
    } finally {
      // 确保锁被释放
      this.isBuildingIndex = false;
    }
  }

  /**
   * 确保索引新鲜度 - 在每次查询前调用
   * 如果索引过期或不存在，自动重建索引
   */
  async ensureIndexFresh() {
    const now = Date.now();
    const isIndexExpired = now - this.lastIndexTime > this.indexTTL;
    const isIndexEmpty = this.userDataCache.size === 0;
    
    if (isIndexExpired || isIndexEmpty) {
      console.log(`🔄 索引需要更新: 过期=${isIndexExpired}, 空=${isIndexEmpty}`);
      await this.buildIndex();
    }
  }

  /**
   * 核心匹配算法 - 使用倒排索引快速筛选候选用户
   * @param {number} currentUserId - 当前用户ID
   * @param {Array} excludeIds - 需要排除的用户ID列表
   * @param {number} limit - 最大返回数量
   * @returns {Array} 候选用户列表
   */
  async findMatchesByIndex(currentUserId, excludeIds, limit = 50) {
    const startTime = Date.now();
    this.metrics.totalQueries++;
    
    try {
      // 步骤1：确保索引新鲜
      await this.ensureIndexFresh();
      
      // 步骤2：获取当前用户数据
      const currentUser = this.userDataCache.get(parseInt(currentUserId));
      if (!currentUser) {
        throw new Error(`当前用户 ${currentUserId} 不在索引中，可能用户数据不满足索引条件`);
      }

      // 步骤3：解析并规范化当前用户课程
      const currentCourses = currentUser.selected_course_names
        .split(',')
        .map(c => this.normalizeCourseName(c));
      
      // 步骤4：使用倒排索引快速找到有共同课程的用户
      const candidateUserIds = new Set();
      
      for (const course of currentCourses) {
        const usersWithCourse = this.courseUserIndex.get(course);
        if (usersWithCourse) {
          // 遍历该课程的所有用户，筛选符合条件的候选用户
          for (const userId of usersWithCourse) {
            const userIdNum = parseInt(userId);
            // 排除条件：自己 + 已排除的用户
            if (userIdNum !== parseInt(currentUserId) && !excludeIds.includes(userIdNum)) {
              candidateUserIds.add(userIdNum);
            }
          }
        }
      }

      console.log(`🔍 索引筛选: 从${currentCourses.length}门课程中找到${candidateUserIds.size}个候选用户`);

      // 步骤5：批量从内存缓存获取候选用户完整数据
      const candidates = [];
      for (const userId of candidateUserIds) {
        const userData = this.userDataCache.get(userId);
        if (userData) {
          candidates.push(userData);
        }
        
        // 限制处理数量，避免性能问题
        if (candidates.length >= limit * 3) {
          console.log(`⚠️ 候选用户数量超过限制: ${limit * 3}，停止收集更多候选用户`);
          break;
        }
      }

      this.metrics.cacheHits++;
      return candidates;

    } catch (error) {
      console.error('❌ 索引匹配失败:', error);
      throw error; // 抛出错误，让上层决定是否降级
    } finally {
      // 记录查询性能
      const duration = Date.now() - startTime;
      if (duration > 1000) {
        console.warn(`🐌 慢查询警告: userId=${currentUserId}, 耗时${duration}ms`);
      }
    }
  }

  /**
   * 课程名称规范化处理
   * 目的：消除课程名称的格式差异，提高匹配准确性
   * @param {string} course - 原始课程名称
   * @returns {string} 规范化后的课程名称
   */
  normalizeCourseName(course) {
    return course
      .trim()
      .toLowerCase()
      .replace(/\s+/g, ' ')          // 统一空格为一个空格
      .replace(/[^\w\s]/g, '')       // 移除标点符号
      .replace(/\s+/g, ' ')          // 再次统一空格
      .trim();
  }

  /**
   * 获取性能指标 - 用于监控系统健康状态
   */
  getMetrics() {
    const cacheHitRate = this.metrics.totalQueries > 0 
      ? (this.metrics.cacheHits / this.metrics.totalQueries * 100).toFixed(2)
      : 0;
      
    return {
      ...this.metrics,
      cacheHitRate: `${cacheHitRate}%`,
      cacheSize: this.userDataCache.size,
      indexSize: this.courseUserIndex.size,
      indexFreshness: Date.now() - this.lastIndexTime
    };
  }
}

// 初始化优化器实例
const matchOptimizer = new MatchOptimizer();

// 系统启动后延迟构建索引（等待数据库就绪）
setTimeout(() => {
  console.log('🔧 系统启动，开始初始化匹配索引...');
  matchOptimizer.buildIndex().catch(error => {
    console.error('❌ 启动时索引构建失败:', error);
  });
}, 5000);

// 定时更新索引（每10分钟）
setInterval(() => {
  console.log('🕒 定时索引更新开始...');
  matchOptimizer.buildIndex().catch(error => {
    console.error('❌ 定时索引更新失败:', error);
  });
}, 10 * 60 * 1000);

/**
 * 优化后的智能匹配学习伙伴接口
 * 执行流程：参数校验 → 获取当前用户 → 排除已匹配用户 → 内存索引匹配 → 计算匹配度 → 排序返回结果
 */
const matchPartners = async (req, res) => {
  const requestStartTime = Date.now();
  
  try {
    const { userId, sortType = 'matchDesc' } = req.query;

    // ==================== 第一步：参数校验 ====================
    if (!userId) {
      return res.send({ status: 400, message: '当前用户ID（userId）不能为空' });
    }
    
    const validSortTypes = ['matchDesc', 'courseDesc'];
    if (!validSortTypes.includes(sortType)) {
      return res.send({ status: 400, message: '排序类型无效，支持 matchDesc/courseDesc' });
    }

    // ==================== 第二步：获取当前用户信息 ====================
    console.log(`👤 开始处理用户 ${userId} 的匹配请求`);
    const getCurrentUserSql = 'SELECT * FROM user_complete_profile WHERE user_id = ?';
    const currentUserResult = await queryDb(getCurrentUserSql, [userId]);
    
    if (currentUserResult.length === 0) {
      return res.send({ status: 404, message: '当前用户不存在' });
    }
    const currentUser = currentUserResult[0];

    // ==================== 第三步：校验用户数据完整性 ====================
    if (!currentUser.study_time || !currentUser.study_style) {
      return res.send({ status: 400, message: '请先完善学习偏好（学习时间和学习风格）' });
    }
    if (!currentUser.selected_course_names) {
      return res.send({ status: 400, message: '请先添加至少一门课程' });
    }

    // ==================== 第四步：获取需要排除的用户ID ====================
    // 排除：已成为伙伴的用户 + 自己
    const getExcludeIdsSql = `
      SELECT partner_id FROM partners WHERE user_id = ? AND status IN (1)
      UNION
      SELECT user_id FROM partners WHERE partner_id = ? AND status IN (1)
    `;
    const excludeResult = await queryDb(getExcludeIdsSql, [userId, userId]);
    const excludeIds = excludeResult.map(item => item.partner_id);
    excludeIds.push(Number(userId));
    
    console.log(`🚫 需要排除的用户数量: ${excludeIds.length}`);

    // ==================== 第五步：获取候选用户 ====================
    let candidates;
    try {
      // 优先使用内存索引快速获取候选用户
      candidates = await matchOptimizer.findMatchesByIndex(userId, excludeIds, 50);
      console.log(`🎯 通过索引找到 ${candidates.length} 个候选用户`);
    } catch (error) {
      // 索引失败时降级到数据库查询
      console.log('🔄 索引匹配失败，回退到数据库查询:', error.message);
      const getCandidatesSql = `
        SELECT * FROM user_complete_profile 
        WHERE user_id NOT IN (${excludeIds.map(() => '?').join(',')})
        AND selected_course_names IS NOT NULL
        AND selected_course_names != ''
        LIMIT 100  -- 限制查询数量，保证性能
      `;
      candidates = await queryDb(getCandidatesSql, excludeIds);
      console.log(`🗃️ 通过数据库查询找到 ${candidates.length} 个候选用户`);
    }

    if (candidates.length === 0) {
      return res.send({ status: 200, data: [], message: '暂无匹配的伙伴' });
    }

    // ==================== 第六步：准备匹配计算数据 ====================
    const currentUserGrade = currentUser.grade;
    const currentPreference = {
      study_time: currentUser.study_time,
      study_style: currentUser.study_style,
      communication_frequency: currentUser.communication_frequency
    };
    const currentCourseNames = currentUser.selected_course_names.split(',');

    // ==================== 第七步：批量计算匹配度 ====================
    console.log(`🧮 开始为 ${candidates.length} 个候选用户计算匹配度`);
    const matchResults = [];
    let skippedCount = 0;
    
    for (const candidate of candidates) {
      const result = fastCalculateMatch(currentUser, candidate, currentCourseNames, currentUserGrade, currentPreference);
      if (result) {
        matchResults.push(result);
      } else {
        skippedCount++;
      }
    }
    
    console.log(`📊 匹配计算完成: 有效结果=${matchResults.length}, 跳过=${skippedCount}`);

    if (matchResults.length === 0) {
      return res.send({ status: 200, data: [], message: '暂无有共同课程的伙伴' });
    }

    // ==================== 第八步：结果排序 ====================
    let sortedResults = [];
    if (sortType === 'courseDesc') {
      // 按共同课程数量降序排序（课程优先）
      sortedResults = matchResults.sort((a, b) => {
        if (a.commonCoursesCount !== b.commonCoursesCount) {
          return b.commonCoursesCount - a.commonCoursesCount; // 课程数多的在前
        }
        return b.totalScore - a.totalScore; // 课程数相同时按总分排序
      });
    } else {
      // 默认按匹配总分降序排序
      sortedResults = matchResults.sort((a, b) => b.totalScore - a.totalScore);
    }

    // ==================== 第九步：返回前9名结果 ====================
    const top9Results = sortedResults.slice(0, 9);
    const totalDuration = Date.now() - requestStartTime;
    
    console.log(`✅ 匹配请求完成: 用户=${userId}, 耗时=${totalDuration}ms, 返回结果=${top9Results.length}个`);

    return res.send({
      status: 200,
      data: top9Results,
      message: top9Results.length > 0 ? `为您找到 ${top9Results.length} 个匹配伙伴` : '暂无有共同课程的伙伴',
      metrics: {
        processedCandidates: candidates.length,
        validMatches: matchResults.length,
        requestDuration: `${totalDuration}ms`
      }
    });

  } catch (err) {
    // 全局错误处理
    console.error('💥 伙伴匹配异常:', err);
    const totalDuration = Date.now() - requestStartTime;
    
    return res.send({ 
      status: 500, 
      message: '匹配失败：系统异常',
      error: process.env.NODE_ENV === 'development' ? err.message : undefined,
      duration: `${totalDuration}ms`
    });
  }
};

/**
 * 快速匹配计算函数 - 核心评分算法
 * 计算三个维度的匹配度：课程匹配(50分) + 学习偏好(40分) + 年级匹配(10分)
 */
function fastCalculateMatch(currentUser, candidate, currentCourseNames, currentUserGrade, currentPreference) {
  // 第一步：数据完整性检查
  if (!candidate.grade || !candidate.study_time || !candidate.selected_course_names) {
    return null; // 跳过数据不完整的候选用户
  }

  // 第二步：使用Set进行快速课程匹配
  const currentCourseSet = new Set(currentCourseNames.map(c => c.toLowerCase().trim()));
  const candidateCourseNames = candidate.selected_course_names.split(',');
  const candidateCourseSet = new Set(candidateCourseNames.map(c => c.toLowerCase().trim()));
  
  // 第三步：计算共同课程（课程匹配的核心）
  const commonCourses = [];
  for (const course of currentCourseSet) {
    if (candidateCourseSet.has(course)) {
      commonCourses.push(course);
    }
  }
  
  // 如果没有共同课程，直接返回null（最重要的筛选条件）
  if (commonCourses.length === 0) {
    return null;
  }

  // 第四步：计算三个维度的匹配分数
  const gradeScore = fastCalculateGradeScore(currentUserGrade, candidate.grade);           // 年级匹配：10分
  const courseScore = fastCalculateCourseScore(currentCourseSet, candidateCourseSet, commonCourses.length); // 课程匹配：50分
  const preferenceScore = fastCalculatePreferenceScore(currentPreference, {              // 学习偏好：40分
    study_time: candidate.study_time,
    study_style: candidate.study_style,
    communication_frequency: candidate.communication_frequency
  });

  // 第五步：计算总分并构建返回结果
  const totalScore = Math.round(courseScore + preferenceScore + gradeScore);

  return {
    userId: candidate.user_id,
    studentId: candidate.student_id,
    grade: candidate.grade,
    major: candidate.major,
    avatar: candidate.avatar,
    nickname: candidate.nickname,
    totalScore,
    commonCoursesCount: commonCourses.length,
    commonCourses,
    scoreBreakdown: { // 分数明细，便于调试和理解
      courseScore: Math.round(courseScore),
      preferenceScore: Math.round(preferenceScore),
      gradeScore: Math.round(gradeScore)
    }
  };
}

/**
 * 计算课程匹配度（满分50分）
 * 基于Jaccard相似度：共同课程数 / 两人中较小的课程总数
 */
function fastCalculateCourseScore(currentCourseSet, candidateCourseSet, commonCount) {
  if (commonCount === 0) return 0;
  
  const minTotal = Math.min(currentCourseSet.size, candidateCourseSet.size);
  const similarity = commonCount / minTotal; // Jaccard相似度
  
  return similarity * 50; // 转换为50分制
}

/**
 * 计算年级匹配度（满分10分）
 * 规则：年级差≤1得10分，否则0分
 */
function fastCalculateGradeScore(currentGrade, candidateGrade) {
  if (!currentGrade || !candidateGrade) return 0;
  
  const gap = Math.abs(currentGrade - candidateGrade);
  return gap <= 1 ? 10 : 0; // 相邻年级或同年级视为匹配
}

/**
 * 计算学习偏好匹配度（满分40分）
 * 包含三个子维度：学习时间(15分) + 学习风格(15分) + 沟通频率(10分)
 */
function fastCalculatePreferenceScore(currentPref, candidatePref) {
  let score = 0;
  
  // 子维度1：学习时间匹配（15分）
  if (currentPref.study_time === candidatePref.study_time) {
    score += 15; // 完全相同：15分
  } else if (isTimeOverlap(currentPref.study_time, candidatePref.study_time)) {
    score += 8;  // 时间段重叠：8分
  }
  
  // 子维度2：学习风格匹配（15分）
  if (currentPref.study_style === candidatePref.study_style) {
    score += 15; // 完全相同：15分
  } else if (isStyleSimilar(currentPref.study_style, candidatePref.study_style)) {
    score += 8;  // 风格相似：8分
  }
  
  // 子维度3：沟通频率匹配（10分）
  if (currentPref.communication_frequency === candidatePref.communication_frequency) {
    score += 10; // 完全相同：10分
  } else if (isFrequencyClose(currentPref.communication_frequency, candidatePref.communication_frequency)) {
    score += 5;  // 频率相近：5分
  }
  
  return score;
}

/**
 * 判断两个学习时间段是否重叠
 */
function isTimeOverlap(time1, time2) {
  const timeRanges = {
    '早8-10点': [8, 10],
    '午12-2点': [12, 14],
    '晚7-9点': [19, 21],
    '晚8-10点': [20, 22],
    '其他': [0, 24]
  };
  
  const [s1, e1] = timeRanges[time1] || [0, 0];
  const [s2, e2] = timeRanges[time2] || [0, 0];
  
  return s1 < e2 && s2 < e1; // 时间段有重叠
}

/**
 * 判断两种学习风格是否相似
 * 相似分组：['安静刷题型', '边学边记型'] 和 ['讨论交流型', '小组协作型']
 */
function isStyleSimilar(style1, style2) {
  const similarGroups = [
    ['安静刷题型', '边学边记型'], // 个人学习型
    ['讨论交流型', '小组协作型']  // 社交学习型
  ];
  
  return similarGroups.some(group => 
    group.includes(style1) && group.includes(style2)
  );
}

/**
 * 判断两种沟通频率是否相近
 * 规则：在频率序列中位置相差≤1视为相近
 */
function isFrequencyClose(freq1, freq2) {
  const freqOrder = ['每周1次', '每周2次', '每天', '按需沟通'];
  const idx1 = freqOrder.indexOf(freq1);
  const idx2 = freqOrder.indexOf(freq2);
  
  return idx1 !== -1 && idx2 !== -1 && Math.abs(idx1 - idx2) <= 1;
}

// 导出接口
module.exports = {
  matchPartners,
  matchOptimizer // 导出优化器实例，便于监控和管理
};